home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-09-20 | 6.7 KB | 322 lines | [TEXT/MMCC] |
- //
- // ADB Key Spy • Pete Gontier • gurgle@apple.com
- // Macintosh Developer Technical Support
- // © 1995 Apple Computer, Inc.
- //
- // See "ADB Key Spy.h" for more information.
- //
- // To do:
- //
- // API to interrogate keyboards one-by-one
- //
- // Changes:
- //
- // when who what
- // --------------------------------------------------------------
- // 08/23/95 PG history begins
- // 08/24/95 PG service routines split off into separate
- // code resource for use with PowerPC
- // 09/11/95 PG first cut at virtual key map support
- //
-
- #ifndef __MEMORY__
- # include <Memory.h>
- #endif
-
- #ifndef __ERRORS__
- # include <Errors.h>
- #endif
-
- #ifndef __LOWMEM__
- # include <LowMem.h>
- #endif
-
- #include "ADB Key Spy.h"
-
- //
- // gKeyboardInfoList
- //
- // This is the head of the linked list mentioned above.
- //
-
- static tKeyboardInfo *gKeyboardInfoList;
-
- //
- // gServiceRoutine
- //
- // This is the detached resource that contains the 68K code
- // which implements the ADB service routine.
- //
-
- static Handle gServiceRoutine;
-
- //
- // GetKMAP
- //
- // The 'KMAP' resources map raw key codes to virtual key codes.
- // To make it possible for the service routine to easily perform
- // this mapping, we toos a handle to the appropriate 'KMAP'
- // resource into each keyboard info record. The resource is
- // marked locked, so it's interrupt-safe.
- //
-
- static pascal OSErr GetKMAP (tKeyboardInfo *kbInfo, char devType)
- {
- //
- // One is not supposed to release resources which potentially come from
- // the System file because they might be shared. Thus, we get our resource
- // and keep it ("leak" it). If you have 'KMAP' resources in some other file
- // for some reason, then you might want to call HomeResFile here to help
- // you decide whether to release the resource.
- //
-
- OSErr err = noErr;
-
- const ResType kmapResType = 'KMAP';
-
- tKeyMapResourceH kmapH = (tKeyMapResourceH) GetResource (kmapResType, devType);
- err = ResError ( );
- if (err == resNotFound || !kmapH)
- {
- kmapH = (tKeyMapResourceH) GetResource (kmapResType, 0);
- err = ResError ( );
- if (err == resNotFound)
- {
- err = noErr;
- kmapH = nil; // just to be sure
- }
- }
-
- kbInfo->keyMapResH = kmapH;
-
- return err;
- }
-
- //
- // AKS_IsKeyDownAnywhere
- //
- // Tests all key maps to see whether the key corresponding to
- // the given key code is down. Pass a value from 0 to 127; higher
- // values produce false.
- //
-
- pascal Boolean AKS_IsKeyDownAnywhere (unsigned char keyCode)
- {
- if (keyCode <= kMaxKeyCode)
- {
- tKeyboardInfo *scan = gKeyboardInfoList;
- while (scan)
- {
- if (scan->virtualKeyMap [keyCode] > 0)
- return true;
-
- scan = scan->next;
- }
- }
-
- return false;
- }
-
- //
- // EnsureHaveServiceRoutine
- //
- // Ensures that the ADB service routine code resource has been loaded
- // into the global variable gServiceRoutine. The resource is loaded low
- // in the heap and locked. It stays loaded forever.
- //
- // 'mySetResLoad' is some cheap glue to make error-handling easier.
- //
-
- static pascal OSErr mySetResLoad (Boolean newLoadValue)
- {
- SetResLoad (newLoadValue);
- return ResError ( );
- }
-
- static pascal OSErr EnsureHaveServiceRoutine (void)
- {
- OSErr err = noErr;
-
- if (!gServiceRoutine)
- {
- Boolean oldResLoad = LMGetResLoad ( );
- if (!oldResLoad || !(err = mySetResLoad (false)))
- {
- gServiceRoutine = Get1Resource ('AKSR',128);
- if (!(err = ResError ( )))
- {
- Size size = GetResourceSizeOnDisk (gServiceRoutine);
- if (!(err = ResError ( )))
- {
- ReserveMem (size);
- if (!(err = MemError ( )))
- {
- LoadResource (gServiceRoutine);
- if (!(err = ResError ( )))
- {
- HLock (gServiceRoutine);
- err = MemError ( );
- }
- }
- }
-
- if (err)
- {
- ReleaseResource (gServiceRoutine);
- gServiceRoutine = nil;
- }
- }
-
- if (oldResLoad)
- {
- OSErr err2 = mySetResLoad (true);
- if (!err) err = err2;
- }
- }
- }
-
- return err;
- }
-
- //
- // AKS_AcquireKeyboards
- //
- // Walks the ADB device list and patches the service routine
- // of each keyboard so that an extra (internal) key map is maintained.
- // A block of memory is allocated via NewPtr for each keyboard.
- //
- // You will probably want to call this function when your app
- // starts and on resume events.
- //
-
- pascal OSErr AKS_AcquireKeyboards (void)
- {
- OSErr err = EnsureHaveServiceRoutine ( );
-
- if (!err)
- {
- ADBSetInfoBlock siBlock;
- ADBDataBlock adbInfo;
-
- short adbCount = CountADBs ( );
-
- while (adbCount)
- {
- ADBAddress adbAddress = GetIndADB (&adbInfo, adbCount);
-
- if (adbAddress < 0)
- {
- DebugStr ("\p adbAddress < 0 ?");
- err = paramErr;
- break;
- }
-
- if (adbInfo.origADBAddr == 2) // 2 == keyboard
- {
- //
- // allocate a new record to track old service proc addresses
- //
-
- tKeyboardInfo *newKeyboardInfo =
- (tKeyboardInfo *) NewPtrClear (sizeof (tKeyboardInfo));
- err = MemError ( );
- if (err) break;
-
- //
- // fill in the new record and (get ready to) push it into our list
- //
-
- err = GetKMAP (newKeyboardInfo, adbInfo.devType);
- if (err)
- {
- DisposePtr ((Ptr) newKeyboardInfo);
- break;
- }
-
- newKeyboardInfo->dbDataAreaAddr = adbInfo.dbDataAreaAddr;
- newKeyboardInfo->dbServiceRtPtr = adbInfo.dbServiceRtPtr;
- newKeyboardInfo->next = gKeyboardInfoList;
-
- //
- // replace the device's service routine and data pointer
- //
-
- siBlock.siService = (ADBServiceRoutineUPP) *gServiceRoutine;
- siBlock.siDataAreaAddr = (Ptr) newKeyboardInfo;
-
- err = SetADBInfo (&siBlock, adbAddress);
- if (err)
- {
- DisposePtr ((Ptr) newKeyboardInfo);
- break;
- }
-
- //
- // push the new record into our list
- //
-
- gKeyboardInfoList = newKeyboardInfo;
- }
-
- --adbCount;
- }
- }
-
- return err;
- }
-
- //
- // AKS_RelinquishKeyboards
- //
- // Walks the private internal list of patched ADB keyboard
- // service routines and unpatches them.
- //
- // You will probably want to call this function when your app
- // quits and on suspend events. If you patch ExitToShell for
- // cleanup during emergency exits, you will want to call this
- // in your patch.
- //
-
- pascal OSErr AKS_RelinquishKeyboards (void)
- {
- OSErr err = noErr;
- short adbCount = CountADBs ( );
- ADBDataBlock adbInfo;
-
- while (gKeyboardInfoList)
- {
- tKeyboardInfo *next = gKeyboardInfoList->next;
- short index = adbCount;
-
- while (index)
- {
- ADBAddress adbAddress = GetIndADB (&adbInfo, index);
-
- if (adbAddress < 0)
- {
- DebugStr ("\p adbAddress < 0 ?");
- err = paramErr;
- break;
- }
-
- if (adbInfo.dbDataAreaAddr == (Ptr) gKeyboardInfoList)
- {
- ADBSetInfoBlock siBlock;
-
- siBlock.siService = gKeyboardInfoList->dbServiceRtPtr;
- siBlock.siDataAreaAddr = gKeyboardInfoList->dbDataAreaAddr;
-
- err = SetADBInfo (&siBlock, adbAddress);
- break;
- }
-
- --index;
- }
-
- DisposePtr ((Ptr) gKeyboardInfoList);
- gKeyboardInfoList = next;
- }
-
- return err;
- }
-